﻿Imports System

Namespace System.Workflow.ComponentModel
    Friend NotInheritable Class TransactedContextFilter
        Inherits ActivityExecutionFilter
        Implements IActivityEventListener([Of] EventArgs), IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs)
        ' Methods
        Public Overrides Function Execute(ByVal activity As Activity, ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            If Not activity.SupportsTransaction Then
                Throw New ArgumentException("activity")
            End If
            activity.RegisterForStatusChange(Activity.LockCountOnStatusChangeChangedEvent, Me)
            activity.HoldLockOnStatusChange(Me)
            Return TransactedContextFilter.ExecuteActivity(activity, executionContext, False)
        End Function

        Private Shared Function ExecuteActivity(ByVal activity As Activity, ByVal context As ActivityExecutionContext, ByVal locksAcquired As Boolean) As ActivityExecutionStatus
            Dim activityExecutorFromType As TransactedContextFilter = DirectCast(ActivityExecutors.GetActivityExecutorFromType(GetType(TransactedContextFilter)), TransactedContextFilter)
            If (Not locksAcquired AndAlso Not context.AcquireLocks(activityExecutorFromType)) Then
                Return activity.ExecutionStatus
            End If
            If (Not TransactedContextFilter.GetTransactionOptions(activity) Is Nothing) Then
                context.CheckpointInstanceState
            End If
            Return activityExecutorFromType.NextActivityExecutorInChain(activity).Execute(activity, context)
        End Function

        Friend Shared Function GetTransactionOptions(ByVal activity As Activity) As WorkflowTransactionOptions
            Return [TryCast](activity.GetValue(If(TypeOf activity Is TransactionScopeActivity, TransactionScopeActivity.TransactionOptionsProperty, CompensatableTransactionScopeActivity.TransactionOptionsProperty)),WorkflowTransactionOptions)
        End Function

        Private Sub OnRevertInstanceState(ByVal sender As Object, ByVal e As EventArgs)
            If (sender Is Nothing) Then
                Throw New ArgumentNullException("sender")
            End If
            If (e Is Nothing) Then
                Throw New ArgumentNullException("e")
            End If
            Dim context As ActivityExecutionContext = [TryCast](sender,ActivityExecutionContext)
            Dim args As StateRevertedEventArgs = [TryCast](e,StateRevertedEventArgs)
            context.Activity.SetValueCommon(ActivityExecutionContext.CurrentExceptionProperty, args.Exception, ActivityExecutionContext.CurrentExceptionProperty.DefaultMetadata, False)
            context.ReleaseLocks(False)
            context.Activity.UnregisterForStatusChange(Activity.LockCountOnStatusChangeChangedEvent, Me)
            context.Activity.ReleaseLockOnStatusChange(Me)
        End Sub

        Private Sub System.Workflow.ComponentModel.IActivityEventListener<System.EventArgs>.OnEvent(ByVal sender As Object, ByVal e As EventArgs) Implements IActivityEventListener([Of] EventArgs).OnEvent
            Dim context As ActivityExecutionContext = DirectCast(sender, ActivityExecutionContext)
            If ((context.Activity.ExecutionStatus = ActivityExecutionStatus.Executing) AndAlso (TransactedContextFilter.ExecuteActivity(context.Activity, context, True) = ActivityExecutionStatus.Closed)) Then
                context.CloseActivity
            End If
        End Sub

        Private Sub System.Workflow.ComponentModel.IActivityEventListener<System.Workflow.ComponentModel.ActivityExecutionStatusChangedEventArgs>.OnEvent(ByVal sender As Object, ByVal e As ActivityExecutionStatusChangedEventArgs) Implements IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs).OnEvent
            Dim context As ActivityExecutionContext = [TryCast](sender,ActivityExecutionContext)
            If (context Is Nothing) Then
                Throw New ArgumentException("sender")
            End If
            If (context.Activity.HasPrimaryClosed AndAlso (context.Activity.LockCountOnStatusChange = 1)) Then
                Dim exception As Exception = DirectCast(context.Activity.GetValue(ActivityExecutionContext.CurrentExceptionProperty), Exception)
                If (Not exception Is Nothing) Then
                    If (Not TransactedContextFilter.GetTransactionOptions(context.Activity) Is Nothing) Then
                        context.RequestRevertToCheckpointState(New EventHandler([Of] EventArgs)(AddressOf Me.OnRevertInstanceState), New StateRevertedEventArgs(exception), False, Nothing)
                    Else
                        context.ReleaseLocks(False)
                        context.Activity.UnregisterForStatusChange(Activity.LockCountOnStatusChangeChangedEvent, Me)
                        context.Activity.ReleaseLockOnStatusChange(Me)
                    End If
                Else
                    Try 
                        context.ReleaseLocks(True)
                        context.Activity.UnregisterForStatusChange(Activity.LockCountOnStatusChangeChangedEvent, Me)
                        context.Activity.ReleaseLockOnStatusChange(Me)
                        context.DisposeCheckpointState
                    Catch obj1 As Object
                        context.Activity.RegisterForStatusChange(Activity.LockCountOnStatusChangeChangedEvent, Me)
                        Throw
                    End Try
                End If
            End If
        End Sub

    End Class
End Namespace

